package com.jesper.seckill.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.exceptions.ValidateException;
import com.alibaba.fastjson.JSONObject;
import com.code.starter.util.RedisUtils;
import com.jesper.seckill.constant.RedisKeyPrefix;
import com.jesper.seckill.entity.po.GoodsSeckill;
import com.jesper.seckill.mapper.GoodsSeckillMapper;
import com.jesper.seckill.entity.po.Order;
import com.jesper.seckill.entity.vo.response.goods.GoodsVO;
import com.jesper.seckill.service.IGoodsSeckillService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jesper.seckill.service.mq.MQMessageProduceService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author sjw
 * @since 2024-01-18
 */
@Service
public class GoodsSeckillServiceImpl extends ServiceImpl<GoodsSeckillMapper, GoodsSeckill> implements IGoodsSeckillService, InitializingBean {

    //做标记，判断商品是否被处理过了
    private HashMap<Long,Boolean> localOverMap = new HashMap<>();

    @Autowired
    private GoodsSeckillMapper goodsSeckillMapper;

    @Autowired
    private MQMessageProduceService mqMessageProduceService;

    /**
     * 三种方式完成Bean初始化后/销毁前操作
     * 第一种：通过实现InitializingBean/DisposableBean
     * 第二种：通过标签init-method/destroy-method
     * 第三种：通过注解@PostConstruct/@PreDestroy
     */
    @Override
    public void afterPropertiesSet(){
        List<GoodsVO> voList = goodsSeckillMapper.getSecKillGoodList();
        //系统初始化，将商品信息加载到redis和本地内存
        if (CollUtil.isEmpty(voList)){
            return;
        }
        for (GoodsVO goodsVO : voList){
            RedisUtils.set(RedisKeyPrefix.getKey(RedisKeyPrefix.SEC_KILL_GOOD_INFO,goodsVO.getId()),goodsVO.getStockCount());
            //初始化商品都是没有处理过的
            localOverMap.put(goodsVO.getId(),false);
        }
    }

    @Override
    public Integer doSeckill(Long goodsId,String userId) {
        //内存标记，减少redis访问
        if (!localOverMap.containsKey(goodsId)){
            throw new ValidateException("商品不存在");
        }
        boolean over = localOverMap.get(goodsId);
        if (over){
            throw new ValidateException("商品已经秒杀完毕");
        }
        //商品预扣减
        long stock = RedisUtils.decr(RedisKeyPrefix.getKey(RedisKeyPrefix.SEC_KILL_GOOD_INFO, goodsId));
        if (stock < 0){
            afterPropertiesSet();
            long stock2 = RedisUtils.decr(RedisKeyPrefix.getKey(RedisKeyPrefix.SEC_KILL_GOOD_INFO, goodsId));
            if (stock2 < 0){
                localOverMap.put(goodsId,true);
                throw new ValidateException("商品已经秒杀完毕");
            }
        }
        //判断重复秒杀
        Order order = RedisUtils.get(RedisKeyPrefix.getKey(RedisKeyPrefix.USER_SUCCESS_SEC_KILL_GOOD_INFO,userId, goodsId), Order.class);
        if (order != null){
            throw new ValidateException("不能重复秒杀");
        }
        //mq异步消费
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("userId",userId);
        jsonObject.put("goodsId",goodsId);
        mqMessageProduceService.sendSeckillMessageToMQ(jsonObject);
        return 0;
    }
}
